// misc win32 functions
#include "burner.h"
#include "misc_win32.h"

// Set the current directory to be the application's directory
int appDirectory()
{
	wchar_t szPath[MAX_PATH] = L"";
	int nLen = 0;
	wchar_t *pc1, *pc2;
	wchar_t* szCmd = GetCommandLine();

	// Find the end of the "c:\directory\program.exe" bit
	if (szCmd[0] == '\"') {						// Filename is enclosed in quotes
		szCmd++;
		for (pc1 = szCmd; *pc1; pc1++) {
			if (*pc1 == '\"') break;			// Find the last "
		}
	} else {
		for (pc1 = szCmd; *pc1; pc1++) {
			if (*pc1 == ' ') break;				// Find the first space
		}
	}
	// Find the last \ or /
	for (pc2 = pc1; pc2 >= szCmd; pc2--) {
		if (*pc2 == '\\') break;
		if (*pc2 == '/') break;
	}

	// Copy the name of the executable into a variable
	nLen = pc1 - pc2 - 1;
	if (nLen > EXE_NAME_SIZE) {
		nLen = EXE_NAME_SIZE;
	}
	wcsncpy(appExeName, pc2 + 1, nLen);
	appExeName[nLen] = 0;

	// strip .exe
	if ((pc1 = wcschr(appExeName, '.')) != 0) {
		*pc1 = 0;
	}

	nLen = pc2 - szCmd;
	if (nLen <= 0) return 1;			// No path

	// Now copy the path into a new buffer
	wcsncpy(szPath, szCmd, nLen);
	SetCurrentDirectory(szPath);		// Finally set the current directory to be the application's directory

	return 0;
}

// ---------------------------------------------------------------------------

// Get the position of the client area of a window on the screen
int getClientScreenRect(HWND hWnd, RECT* rect)
{
	POINT corner = { 0, 0 };

	GetClientRect(hWnd, rect);
	if (!vidFullscreen) {
		ClientToScreen(hWnd, &corner);
	}

	rect->left += corner.x;
	rect->right += corner.x;
	rect->top += corner.y;
	rect->bottom += corner.y;

	return 0;
}

// Put a window in the middle of another window
int wndInMid(HWND hMid, HWND hBase)
{
	RECT midRect = {0, 0, 0, 0};
	int mw = 0, mh = 0;
	RECT baseRect = {0, 0, 0, 0};
	int bx = 0, by = 0;

	// Find the height and width of the Mid window
	GetWindowRect(hMid, &midRect);
	mw = midRect.right - midRect.left;
	mh = midRect.bottom - midRect.top;

	// Find the center of the Base window
	if (hBase && IsWindowVisible(hBase)) {
		GetWindowRect(hBase, &baseRect);
		if (hBase == hScrnWnd) {
			// For the main window, center in the client area.
			baseRect.left += GetSystemMetrics(SM_CXSIZEFRAME);
			baseRect.right -= GetSystemMetrics(SM_CXSIZEFRAME);
			baseRect.top += GetSystemMetrics(SM_CYSIZEFRAME);
			if (menuEnabled) {
				baseRect.top += GetSystemMetrics(SM_CYCAPTION);
			}
			baseRect.bottom -= GetSystemMetrics(SM_CYSIZEFRAME);
		}
	} else {
		SystemParametersInfo(SPI_GETWORKAREA, 0, &baseRect, 0);
	}

	bx = baseRect.left + baseRect.right;
	bx = (bx - mw) >> 1;
	by = baseRect.top + baseRect.bottom;
	by = (by - mh) >> 1;

	if (hBase) {
		SystemParametersInfo(SPI_GETWORKAREA, 0, &systemWorkArea, 0);

		if (bx + mw > systemWorkArea.right) {
			bx = systemWorkArea.right - mw;
		}
		if (by + mh > systemWorkArea.bottom) {
			by = systemWorkArea.bottom - mh;
		}
		if (bx < systemWorkArea.left) {
			bx = systemWorkArea.left;
		}
		if (by < systemWorkArea.top) {
			by = systemWorkArea.top;
		}
	}

	// Center the window
	SetWindowPos(hMid, NULL, bx, by, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

	return 0;
}

// ==> other functions, added by regret
void setWindowAspect()
{
	int width = GetSystemMetrics(SM_CXSCREEN);
	int height = GetSystemMetrics(SM_CYSCREEN);
	if (width <= 0 || height <= 0) {
		return;
	}

	if (vidAutoScrnAspect) {
		vidScrnAspect = (double)width / (double)height;
	} else {
		vidScrnAspect = (double)vidScrnAspectX / (double)vidScrnAspectY;
	}
}

double getWindowAspect()
{
	int width = GetSystemMetrics(SM_CXSCREEN);
	int height = GetSystemMetrics(SM_CYSCREEN);
	if (width <= 0 || height <= 0) {
		return 0.0f;
	}

	return (double)width / (double)height;
}

void createNeedDir()
{
	CreateDirectory(L"config", NULL);
	CreateDirectory(L"config\\games", NULL);
	CreateDirectory(L"config\\presets", NULL);
	CreateDirectory(L"config\\ips", NULL); // ips config
}

bool directoryExists(const wchar_t* dirname)
{
	if (!dirname) {
		return false;
	}

	DWORD res = GetFileAttributes(dirname);
	return res != 0xFFFFFFFF && res & FILE_ATTRIBUTE_DIRECTORY;
}

int directLoadGame(wchar_t* name)
{
	if (!name) {
		return 1;
	}

	if (fullscreenOnStart) {
		vidFullscreen = 1;
	}

	if (_wcsicmp(&name[wcslen(name) - 3], L".fs") == 0) {
		if (BurnStateLoad(name, 1, &drvInitCallback)) {
			return 1;
		}
	}
	else if (_wcsicmp(&name[wcslen(name) - 3], L".fr") == 0) {
		if (startReplay(name)) {
			return 1;
		}
	}
	else {
		// get game name
		wchar_t* p = getBaseName(name);

		// load game
		unsigned int i = BurnDrvGetIndexByNameA(WtoA(p));
		if (i < BurnGetDrvCount()) {
			BurnerDrvInit(i, true);
		}
	}

	return 0;
}

// create dialog item tooltip
bool createToolTip(int toolID, HWND hDlg, wchar_t* pText)
{
	// toolID:   the resource ID of the control.
	// hDlg:     the handle of the dialog box.
	// pText:    the text that appears in the tooltip.
	// hAppInst: the global instance handle.

	if (!toolID || !hDlg || !pText) {
		return false;
	}

	// Get the window of the tool.
	HWND hwndTool = GetDlgItem(hDlg, toolID);

	// Create the tooltip.
	HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
								WS_POPUP | TTS_ALWAYSTIP,
								CW_USEDEFAULT, CW_USEDEFAULT,
								CW_USEDEFAULT, CW_USEDEFAULT,
								hDlg, NULL,
								hAppInst, NULL);

	if (!hwndTool || !hwndTip) {
		return false;
	}

	// Associate the tooltip with the tool.
	TOOLINFO toolInfo = { 0 };
	toolInfo.cbSize = sizeof(toolInfo);
	toolInfo.hwnd = hDlg;
	toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
	toolInfo.uId = (UINT_PTR)hwndTool;
	toolInfo.lpszText = pText;
	SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);

	return true;
}

int commonFileDialog(HWND owner, bool save, const wchar_t* title, const wchar_t* filter, const wchar_t* dir, const wchar_t* ext)
{
	splashDestroy(true);

	if (driverOkay) {
		audioInterface.stop();
	}

	memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = owner;
	ofn.lpstrFile = commonChoice;
	ofn.nMaxFile = sizearray(commonChoice);
	ofn.Flags = OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
	if (save) {
		ofn.Flags |= OFN_OVERWRITEPROMPT;
	}
	if (title) ofn.lpstrTitle = title;
	if (filter) {
		ofn.lpstrFilter = filter;
	} else {
		ofn.lpstrFilter = L"All Files (*)\0*.*\0\0";
	}
	if (dir) ofn.lpstrInitialDir = dir;
	if (ext) ofn.lpstrDefExt = ext;

	int oldPause = runPause;
	runPause = 1;
	int ret = 0;
	if (save) {
		ret = GetSaveFileName(&ofn);
	} else {
		ret = GetOpenFileName(&ofn);
	}
	runPause = oldPause;

	if (driverOkay) {
		audioInterface.play();
	}

	if (ret == 0) return 1;
	return 0;
}
// <== other functions

// ---------------------------------------------------------------------------
// For DAT files printing and Kaillera windows

char* decorateGameName(unsigned int drv)
{
	if (drv >= BurnGetDrvCount())
		return "";

	// get game full name
	static char decoratedName[1024] = "";
	strcpy(decoratedName, BurnDrvGetTextA(DRV_FULLNAME, drv));

	// get game extra info
	char gameInfo[256] = " [";
	bool hasInfo = false;

	if (BurnDrvGetFlags(drv) & BDF_PROTOTYPE) {
		strcat(gameInfo, "prototype");
		hasInfo = true;
	}
	if (BurnDrvGetFlags(drv) & BDF_BOOTLEG) {
		strcat(gameInfo, "bootleg");
		hasInfo = true;
	}
	if (BurnDrvGetTextA(DRV_COMMENT, drv)) {
		strcat(gameInfo, BurnDrvGetTextA(DRV_COMMENT, drv));
		hasInfo = true;
	}

	if (hasInfo) {
		strcat(gameInfo, "]");
		strcat(decoratedName, gameInfo);
	}

	return decoratedName;
}

char* decorateKailleraGameName(unsigned int drv)
{
	if (drv >= BurnGetDrvCount())
		return "";

	// get game full name, modified by regret
	static char decoratedName[1024] = "";
	sprintf(decoratedName, "%s [%s]", BurnDrvGetTextA(DRV_FULLNAME, drv), BurnDrvGetTextA(DRV_NAME, drv));
	return decoratedName;
}

// rom util
static inline int findRomByName(const char* name, ArcEntry* list, int count)
{
	if (!name || !list) {
		return -1;
	}

	// Find the rom named name in the List
	for (int i = 0; i < count; i++, list++) {
		if (list->szName && !_stricmp(name, getFilenameA(list->szName))) {
			return i;
		}
	}
	return -1; // couldn't find the rom
}

static inline int findRomByCrc(unsigned int crc, ArcEntry* list, int count)
{
	if (!list) {
		return -1;
	}

	// Find the rom named name in the List
	for (int i = 0; i < count; i++, list++)	{
		if (crc == list->nCrc) {
			return i;
		}
	}

	return -1; // couldn't find the rom
}

// Find rom number i from the pBArchiveDriver game
int findRom(int i, ArcEntry* list, int count, unsigned drvIndex)
{
	BurnRomInfo ri;
	memset(&ri, 0, sizeof(ri));

	int ret = BurnDrvGetRomInfo(&ri, i, drvIndex);
	if (ret != 0) {								// Failure: no such rom
		return -2;
	}

	if (ri.nCrc) {								// Search by crc first
		ret = findRomByCrc(ri.nCrc, list, count);
		if (ret >= 0) {
			return ret;
		}
	}

	for (int aka = 0; aka < 0x10000; aka++) {	// Failing that, search for possible names
		char* possibleName = NULL;
		ret = BurnDrvGetRomName(&possibleName, i, aka, drvIndex);
		if (ret) {								// No more rom names
			break;
		}
		ret = findRomByName(possibleName, list, count);
		if (ret >= 0) {
			return ret;
		}
	}

	return -1; // Couldn't find the rom
}
